package wortubung.lang;

import static wortubung.util.CommonUtils.*;
import static wortubung.util.JSONUtils.getString;
import static wortubung.util.JSONUtils.getStringArray;
import static wortubung.util.LatinScript.enAccent;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.json.JSONObject;

import wortubung.core.LANG;
import wortubung.inflection.CONJUGATION;
import wortubung.inflection.ConjugationResult;
import wortubung.inflection.ConjugationSet;
import wortubung.inflection.DerivedVerbConjugation;
import wortubung.inflection.IrregularVerbCache;
import wortubung.inflection.VerbConjugation;
import wortubung.util.TransliterateException;

public abstract class ConjugatorBase {
	
	protected abstract String[] conjugate(String verbeSuffix, CONJUGATION conjType, boolean langSpecificFlag);
	protected abstract String participle(String verbeSuffix, boolean isPresent);
	public abstract LANG getLanguage();

	protected Map<String,String> irregularFutureRoots = new HashMap<String,String>(); // also used by conditional by most languages here.
	protected IrregularVerbCache irregularVerbCache = new IrregularVerbCache();

	protected Properties readInitFiles(String propsFile, String asIsConjugationFile) {
		Properties props = null;
		try {
			if (propsFile != null) {
				props = readPropertiesFromCP(propsFile);
	    		// Read special future stems
	    		readNameValuePairs(irregularFutureRoots, props.getProperty("future_stems"), true);
			}

			if (asIsConjugationFile != null) {
	    		// Read as-is irregulars from the resource (JSON) file
	    		irregularVerbCache.readFromJSON(asIsConjugationFile, getLanguage());
			}

    		// More specific initializations, which could be based off props or anything else.
    		furtherInit(props);

    		// Add all verbs with irregular roots into irregularVerbCache
    		for (String verb : irregularFutureRoots.keySet())
    			irregularVerbCache.addIrregularConjugation(getConjugation(verb));

		} catch(Exception e) {
			e.printStackTrace();
		}

		return props;
	}

	protected void readNameValuePairs(Map<String,String> result, String pairs, boolean enAccent) throws TransliterateException {
		readNameValuePairs(result, pairs, ",", "\\|", enAccent);
	}

	protected void readNameValuePairs(Map<String,String> result, String pairs, String pairSep, String nameValueSep, boolean enAccent) throws TransliterateException {
		if (isEmpty(pairs))
			return;
		for (String nv : pairs.split(pairSep)) {
			String[] sa = nv.split(nameValueSep);
			String name = sa[0].trim();
			String val = sa[1].trim();
			if (enAccent)
				result.put(getLanguage().toVernacular(name), getLanguage().toVernacular(val));
			else
				result.put(name, val);
		}
	}

	protected void readValues(Set<String> result, String values, boolean enAccent) throws TransliterateException {
		readValues(result, values, ",", enAccent);
	}

	protected void readValues(Set<String> result, String values, String valueSep, boolean enAccent) throws TransliterateException {
		if (isEmpty(values))
			return;
		for (String v : values.split(valueSep)) {
			v = v.trim();
			result.add(enAccent ? getLanguage().toVernacular(v) : v);
		}
	}

	protected void furtherInit(Properties props) throws IOException, TransliterateException {
	}

	public String getIrregularFutureRoot(String verb) {
		return irregularFutureRoots.get(verb);
	}

	public VerbConjugation getIrregulerConjugator(String verb) {
		return irregularVerbCache.getIrregularConjugation(verb);
	}

	public void addIrregulerConjugation(VerbConjugation conjugation) {
		irregularVerbCache.addIrregularConjugation(conjugation);
	}

	public String getIrregulerSuffix(String verb) {
		return irregularVerbCache.getSuffix(verb);
	}

	public Collection<String> getVerbsOfIrregularConjugations() {
		return irregularVerbCache.getVerbs();
	}

	public Collection<VerbConjugation> getIrregularConjugations(boolean sorted) {
		return irregularVerbCache.getConjugations(sorted, getLanguage());
	}

	public VerbConjugation getConjugation(String verb) {
		VerbConjugation vc = getIrregulerConjugator(verb);
		if (vc != null)
			return vc.getConjugationResult(null);

		String[] prefixSuffix = getPrefixSuffixForIrregular(verb);
		vc = getIrregulerConjugator(prefixSuffix[1]);
		if (vc == null)
			return conjugate(prefixSuffix[0], prefixSuffix[1]);
		if (prefixSuffix[0] == null)
			return vc;
		return new DerivedVerbConjugation(prefixSuffix[0], vc);
	}

	public VerbConjugation conjugate(String prefix, String verbeSuffix) {
		ConjugationResult ret = new ConjugationResult(verbeSuffix);

		ConjugationSet cs = new ConjugationSet(ret, participle(verbeSuffix, true), participle(verbeSuffix, false));
		CONJUGATION[] conjs = CONJUGATION.forLanguage(getLanguage());
		for (CONJUGATION type : conjs) {
			boolean extraFlag = (getLanguage() == LANG.fr);
			String[] conj = conjugate(verbeSuffix, type, extraFlag);
			if (conj != null)
				cs.add(type, conj);
		}
		ret.addConjugationSet(cs);

		postProcess(ret, verbeSuffix);

		if (prefix == null)
			return ret;
		return new DerivedVerbConjugation(prefix, ret);
	}

	protected void postProcess(VerbConjugation result, String verbSuffix) {
	}

	public String[] getPrefixSuffixForIrregular(String verb) {
		String[] result = { null, verb };
		String verbSuffix = getIrregulerSuffix(verb);
		if (verbSuffix == null || verb.length() == verbSuffix.length())
			return result;
		result[0] = chopRight(verb, verbSuffix.length());
		result[1] = verbSuffix;
		return result;
	}


	public static String[] getRomanStringArray(JSONObject json, String key) {
		String[] sa = getStringArray(json, key);
		enAccent(sa);
		return sa;
	}

	public static String getRomanString(JSONObject json, String key, String defaultValue) {
		return enAccent(getString(json, key, defaultValue));
	}
}
